package cn.mania_man.service.web_socket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Component
@ServerEndpoint(value = "/ws/{roomId}/{userName}/{role}")

public class WebSocket {
    public static final Map<String, Map<String, WebSocket>> websockets = new ConcurrentHashMap<String, Map<String, WebSocket>>();
    private Session session;
    private String userName;
    private String role;

    private String roomId;

    private String KPName = "";

    @OnOpen
    public void open(@PathParam("roomId") String roomId, @PathParam("userName") String userName,
                     @PathParam("role") String role, Session session) {

        //基本数据
        this.session = session;
        this.userName = userName;
        this.role = role;
        this.roomId = roomId;

        //存入websockets
        if (websockets.get(roomId) == null) {
            websockets.put(roomId, new ConcurrentHashMap<String, WebSocket>());
        }
        websockets.get(roomId).put(userName, this);

        //作初始化处理
        ArrayList<String> arrayList= new ArrayList<>();
        for (WebSocket webSocket:websockets.get(roomId).values()
        ) {
            arrayList.add(webSocket.userName);
        }
        sendToRoom(roomId, getMessageJson(userName + "作为" + role + "加入了,在线者:"
                +arrayList.stream().map(String::valueOf).collect(Collectors.joining(","))));

        //初始化数据:向KP发送数据同步请求
        WebSocket KP = getKp();
        if (KP != null) {
            Map<Object, Object> map = new HashMap<>();
            map.put("type", "init_room");
            map.put("init_user", userName);
            KP.sendToUser(JSON.toJSONString(map));
        } else {
            if (Objects.equals(this.role, "KP")) {
                Map<Object, Object> map = new HashMap<>();
                map.put("type", "init_room");
                map.put("init_user", "$*");
                this.sendToUser(JSON.toJSONString(map));
            }
        }

    }

    @OnMessage
    public void message(String message, Session session) {
        JSONObject messageObj = JSONObject.parseObject(message);
        switch (messageObj.get("type").toString()){
            case "init_room":{
                if (!this.isKP()){
                    sendToUser(getMessageJson("非kp身份，无法修改数据"));
                    break;
                }
                Map<Object,Object> map=new HashMap<>();
                map.put("type","init_room");
                map.put("init_user", "$self");
                map.put("data",messageObj.get("data").toString());
                if(Objects.equals(messageObj.get("init_user").toString(), "$*")){
                    sendToRoom(this.roomId,JSON.toJSONString(map),this);
                    break;
                }
                System.out.println(messageObj.get("init_user").toString());
                WebSocket user=websockets.get(roomId).get(messageObj.get("init_user").toString());
                if (user!=null){
                    user.sendToUser(JSON.toJSONString(map));
                }
                break;
            }
            case "card_add": case "card_delete": case "card_update":{
                if (!this.isKP()){
                    sendToUser(getMessageJson("非kp身份，无法修改数据"));
                    break;
                }
                sendToRoom(roomId,message,this);
                break;
            }
            default:{
                sendToUser(getMessageJson("错误的输入,type不匹配"));
            }
        }

    }

    @OnClose
    public void onClose() {
        //作初始化处理

        websockets.get(roomId).remove(userName);
        if (websockets.get(roomId).size() == 0) {
            websockets.remove(roomId);
            return;
        }
        ArrayList<String> arrayList= new ArrayList<>();
        for (WebSocket webSocket:websockets.get(roomId).values()
             ) {
            arrayList.add(webSocket.userName);
        }
        sendToRoom(roomId, getMessageJson(role + ":" + userName + "退出了,剩余"+
                arrayList.stream().map(String::valueOf).collect(Collectors.joining(","))));
    }

    void sendToUser(String text) {
        try {
            session.getBasicRemote().sendText(text);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    static void sendToList(Iterable<WebSocket> users, String text) {
        for (WebSocket user : users
        ) {
            user.sendToUser(text);
        }
    }

    static void sendToRoom(String roomId, String text) {
        sendToRoom(roomId,text,null);
    }
    static void sendToRoom(String roomId, String text, WebSocket skipUser) {
        Map<String, WebSocket> map = websockets.get(roomId);
        if (map == null){
            return;
        }
        Collection<WebSocket> collection = new ArrayList<>(map.values());
        if (skipUser!=null) collection.remove(skipUser);
        sendToList(collection, text);
    }

    String getMessageJson(String text) {
        Map<Object, Object> message = new HashMap<>();
        message.put("type", "message");
        message.put("date", new SimpleDateFormat("yy-MM-dd HH:mm:ss").format(new Date()));
        message.put("text", text);
        return JSON.toJSONString(message);
    }

    WebSocket getKp() {
        Map<String, WebSocket> room = websockets.get(this.roomId);
        WebSocket KP = room.get(KPName);
        if (KP != null) {
            return KP;
        }
        for (WebSocket user : room.values()
        ) {
            WebSocket userKP = room.get(user.KPName);
            if (userKP!=null) {
                this.KPName = user.KPName;
                if (Objects.equals(this.KPName, this.userName)) {
                    return null;
                }
                return userKP;
            }
        }
        for (WebSocket user : room.values()
        ) {
            if (user.isKP()) {
                this.KPName = user.userName;
                if (Objects.equals(this.KPName, this.userName)) {
                    return null;
                }
                return user;
            }
        }
        return null;
    }

    boolean isKP(){
        return Objects.equals("KP",this.role);
    }
}
